{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Nodejs Tensorflow Example\n",
    "\n",
    " * Wrap a nodejs tensorflow model for use as a prediction microservice in seldon-core\n",
    "   * Run locally on Docker to test\n",
    " \n",
    "## Dependencies\n",
    "\n",
    " * ```pip install seldon-core```\n",
    " * [Helm](https://github.com/kubernetes/helm)\n",
    " * [Minikube](https://github.com/kubernetes/minikube)\n",
    " * [S2I](https://github.com/openshift/source-to-image)\n",
    " * node (version>=8.11.0)\n",
    " * npm\n",
    "\n",
    "## Train locally using npm commands\n",
    "This model example takes an input of 10 different features and predicts a out for the same. For the training part it uses a random normally distributed input set of 100 rows i.e a data set of [100,10] and trains it for another random normally distributed data set of size [100,1]. For every prediction the model expects a dataset of dimension [r,10] where r is the num of input rows to be predicted."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "npm install\n",
      "\u001b[K\u001b[?25h        \u001b[27m\u001b[90m......\u001b[0m] \\ refresh-package-json:@tensorflow/tfjs-node: \u001b[32;40mtiming\u001b[0m \u001b[35mactio\u001b[0m\u001b[Km\u001b[K\n",
      "> @tensorflow/tfjs-node@0.1.15 install /home/clive/work/seldon-core/fork-seldon-core/examples/models/nodejs_tensorflow/node_modules/@tensorflow/tfjs-node\n",
      "> node scripts/install.js\n",
      "\n",
      "* Downloading libtensorflow\n",
      "\u001b[1G[                              ] Infinity/bps 0% 0.0s\u001b[0K\u001b[1G[                              ] 154364/bps 0% 128.0s\u001b[0K\u001b[1G[                              ] 1240158/bps 0% 15.9s\u001b[0K\u001b[1G[                              ] 3603148/bps 0% 5.4s\u001b[0K\u001b[1G[=                             ] 4762971/bps 1% 4.1s\u001b[0K\u001b[1G[=                             ] 5481686/bps 2% 3.5s\u001b[0K\u001b[1G[=                             ] 6214471/bps 3% 3.1s\u001b[0K\u001b[1G[=                             ] 6967373/bps 4% 2.7s\u001b[0K\u001b[1G[=                             ] 7131544/bps 4% 2.6s\u001b[0K\u001b[1G[==                            ] 6972763/bps 5% 2.7s\u001b[0K\u001b[1G[==                            ] 9257518/bps 7% 2.0s\u001b[0K\u001b[1G[===                           ] 11301908/bps 10% 1.6s\u001b[0K\u001b[1G[====                          ] 12855355/bps 13% 1.3s\u001b[0K\u001b[1G[=====                         ] 14330366/bps 15% 1.2s\u001b[0K\u001b[1G[======                        ] 15672547/bps 18% 1.0s\u001b[0K\u001b[1G[======                        ] 16246964/bps 20% 1.0s\u001b[0K\u001b[1G[======                        ] 5880849/bps 21% 2.6s\u001b[0K\u001b[1G[=======                       ] 6088044/bps 22% 2.5s\u001b[0K\u001b[1G[=======                       ] 6089241/bps 23% 2.5s\u001b[0K\u001b[1G[=======                       ] 6240503/bps 24% 2.4s\u001b[0K\u001b[1G[========                      ] 6469579/bps 25% 2.3s\u001b[0K\u001b[1G[========                      ] 6936442/bps 27% 2.1s\u001b[0K\u001b[1G[=========                     ] 7304197/bps 30% 1.9s\u001b[0K\u001b[1G[==========                    ] 7668265/bps 32% 1.7s\u001b[0K\u001b[1G[==========                    ] 8104748/bps 34% 1.6s\u001b[0K\u001b[1G[===========                   ] 8582095/bps 37% 1.4s\u001b[0K\u001b[1G[============                  ] 9004661/bps 39% 1.3s\u001b[0K\u001b[1G[=============                 ] 9577209/bps 43% 1.2s\u001b[0K\u001b[1G[==============                ] 9949360/bps 45% 1.1s\u001b[0K\u001b[1G[==============                ] 10078374/bps 47% 1.0s\u001b[0K\u001b[1G[===============               ] 10481581/bps 49% 0.9s\u001b[0K\u001b[1G[================              ] 10819946/bps 52% 0.9s\u001b[0K\u001b[1G[================              ] 11096666/bps 54% 0.8s\u001b[0K\u001b[1G[=================             ] 11347867/bps 56% 0.8s\u001b[0K\u001b[1G[==================            ] 11607371/bps 59% 0.7s\u001b[0K\u001b[1G[==================            ] 11842695/bps 61% 0.6s\u001b[0K\u001b[1G[===================           ] 12102357/bps 63% 0.6s\u001b[0K\u001b[1G[====================          ] 12291890/bps 65% 0.6s\u001b[0K\u001b[1G[====================          ] 12552382/bps 67% 0.5s\u001b[0K\u001b[1G[=====================         ] 12774990/bps 70% 0.5s\u001b[0K\u001b[1G[======================        ] 12976247/bps 72% 0.4s\u001b[0K\u001b[1G[======================        ] 13042719/bps 73% 0.4s\u001b[0K\u001b[1G[=======================       ] 13306582/bps 76% 0.4s\u001b[0K\u001b[1G[========================      ] 13591597/bps 79% 0.3s\u001b[0K\u001b[1G[========================      ] 13784480/bps 81% 0.3s\u001b[0K\u001b[1G[=========================     ] 13861252/bps 82% 0.2s\u001b[0K\u001b[1G[==========================    ] 14045382/bps 85% 0.2s\u001b[0K\u001b[1G[==========================    ] 14251651/bps 87% 0.2s\u001b[0K\u001b[1G[===========================   ] 14372631/bps 89% 0.1s\u001b[0K\u001b[1G[============================  ] 14648295/bps 92% 0.1s\u001b[0K\u001b[1G[============================  ] 14670301/bps 93% 0.1s\u001b[0K\u001b[1G[============================  ] 14564979/bps 94% 0.1s\u001b[0K\u001b[1G[============================= ] 14524195/bps 95% 0.1s\u001b[0K\u001b[1G[============================= ] 14460878/bps 96% 0.1s\u001b[0K\u001b[1G[============================= ] 14434699/bps 97% 0.0s\u001b[0K\u001b[1G[============================= ] 14384762/bps 97% 0.0s\u001b[0K\u001b[1G[==============================] 14313428/bps 98% 0.0s\u001b[0K\u001b[1G[==============================] 14325589/bps 99% 0.0s\u001b[0K\u001b[1G[==============================] 14319896/bps 100% 0.0s\u001b[0K\n",
      "* Building TensorFlow Node.js bindings\n",
      "\n",
      "> protobufjs@6.8.8 postinstall /home/clive/work/seldon-core/fork-seldon-core/examples/models/nodejs_tensorflow/node_modules/protobufjs\n",
      "> node scripts/postinstall\n",
      "\n",
      "\u001b[37;40mnpm\u001b[0m \u001b[0m\u001b[34;40mnotice\u001b[0m\u001b[35m\u001b[0m created a lockfile as package-lock.json. You should commit this file.\n",
      "\u001b[0m\u001b[37;40mnpm\u001b[0m \u001b[0m\u001b[30;43mWARN\u001b[0m\u001b[35m\u001b[0m nodejs_tensorflow@1.0.0 No repository field.\n",
      "\u001b[0m\u001b[37;40mnpm\u001b[0m \u001b[0m\u001b[30;43mWARN\u001b[0m\u001b[35m\u001b[0m nodejs_tensorflow@1.0.0 No license field.\n",
      "\u001b[0m\n",
      "added 48 packages from 56 contributors and audited 61 packages in 9.829s\n",
      "found \u001b[92m0\u001b[0m vulnerabilities\n",
      "\n",
      "npm start\n",
      "\n",
      "> nodejs_tensorflow@1.0.0 start /home/clive/work/seldon-core/fork-seldon-core/examples/models/nodejs_tensorflow\n",
      "> node train.js\n",
      "\n",
      "2019-05-10 06:56:33.691232: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA\n",
      "Epoch 0: loss = 1.1140578985214233\n",
      "Epoch 1: loss = 1.0404443740844727\n",
      "Epoch 2: loss = 1.0114623308181763\n",
      "Epoch 3: loss = 0.994644284248352\n",
      "Epoch 4: loss = 0.9810447692871094\n",
      "Epoch 5: loss = 0.9564876556396484\n",
      "Epoch 6: loss = 0.947548508644104\n",
      "Epoch 7: loss = 0.9377892017364502\n",
      "Epoch 8: loss = 0.9292038679122925\n",
      "Epoch 9: loss = 0.9103612899780273\n",
      "Epoch 10: loss = 0.9044468402862549\n",
      "Epoch 11: loss = 0.8943670392036438\n",
      "Epoch 12: loss = 0.8909915685653687\n",
      "Epoch 13: loss = 0.8821757435798645\n",
      "Epoch 14: loss = 0.8772059679031372\n",
      "Epoch 15: loss = 0.8722608685493469\n",
      "Epoch 16: loss = 0.870168149471283\n",
      "Epoch 17: loss = 0.8628248572349548\n",
      "Epoch 18: loss = 0.856920599937439\n",
      "Epoch 19: loss = 0.8508269786834717\n",
      "Epoch 20: loss = 0.8445506691932678\n",
      "Epoch 21: loss = 0.8388644456863403\n",
      "Epoch 22: loss = 0.8324810862541199\n",
      "Epoch 23: loss = 0.8312572836875916\n",
      "Epoch 24: loss = 0.8251888155937195\n",
      "Epoch 25: loss = 0.8173127770423889\n",
      "Epoch 26: loss = 0.8206360936164856\n",
      "Epoch 27: loss = 0.825434684753418\n",
      "Epoch 28: loss = 0.8106041550636292\n",
      "Epoch 29: loss = 0.8014734387397766\n",
      "Epoch 30: loss = 0.7964511513710022\n",
      "Epoch 31: loss = 0.7898756265640259\n",
      "Epoch 32: loss = 0.7860068082809448\n",
      "Epoch 33: loss = 0.7900837659835815\n",
      "Epoch 34: loss = 0.7788155674934387\n",
      "Epoch 35: loss = 0.778168261051178\n",
      "Epoch 36: loss = 0.774094820022583\n",
      "Epoch 37: loss = 0.7649340033531189\n",
      "Epoch 38: loss = 0.759834349155426\n",
      "Epoch 39: loss = 0.7585961818695068\n",
      "Epoch 40: loss = 0.7511364817619324\n",
      "Epoch 41: loss = 0.7497982382774353\n",
      "Epoch 42: loss = 0.7454034090042114\n",
      "Epoch 43: loss = 0.7422577738761902\n",
      "Epoch 44: loss = 0.7390987873077393\n",
      "Epoch 45: loss = 0.7328671813011169\n",
      "Epoch 46: loss = 0.7296737432479858\n",
      "Epoch 47: loss = 0.7255033850669861\n",
      "Epoch 48: loss = 0.7259540557861328\n",
      "Epoch 49: loss = 0.7198896408081055\n",
      "Epoch 50: loss = 0.7157299518585205\n",
      "Epoch 51: loss = 0.7137295603752136\n",
      "Epoch 52: loss = 0.7115896344184875\n",
      "Epoch 53: loss = 0.7110546827316284\n",
      "Epoch 54: loss = 0.7083038687705994\n",
      "Epoch 55: loss = 0.7007032036781311\n",
      "Epoch 56: loss = 0.6936700344085693\n",
      "Epoch 57: loss = 0.693160891532898\n",
      "Epoch 58: loss = 0.6876615881919861\n",
      "Epoch 59: loss = 0.6804297566413879\n",
      "Epoch 60: loss = 0.6776358485221863\n",
      "Epoch 61: loss = 0.6728461980819702\n",
      "Epoch 62: loss = 0.6687815189361572\n",
      "Epoch 63: loss = 0.6673902869224548\n",
      "Epoch 64: loss = 0.6670713424682617\n",
      "Epoch 65: loss = 0.6624063849449158\n",
      "Epoch 66: loss = 0.65739905834198\n",
      "Epoch 67: loss = 0.6553966999053955\n",
      "Epoch 68: loss = 0.6506110429763794\n",
      "Epoch 69: loss = 0.6493582129478455\n",
      "Epoch 70: loss = 0.6465271711349487\n",
      "Epoch 71: loss = 0.6439094543457031\n",
      "Epoch 72: loss = 0.6397424340248108\n",
      "Epoch 73: loss = 0.6372050046920776\n",
      "Epoch 74: loss = 0.6370261907577515\n",
      "Epoch 75: loss = 0.6327844858169556\n",
      "Epoch 76: loss = 0.6300538182258606\n",
      "Epoch 77: loss = 0.6324681639671326\n",
      "Epoch 78: loss = 0.6271001100540161\n",
      "Epoch 79: loss = 0.6215335130691528\n",
      "Epoch 80: loss = 0.6228755116462708\n",
      "Epoch 81: loss = 0.6215202808380127\n",
      "Epoch 82: loss = 0.6156829595565796\n",
      "Epoch 83: loss = 0.6130117774009705\n",
      "Epoch 84: loss = 0.6068021655082703\n",
      "Epoch 85: loss = 0.6044408082962036\n",
      "Epoch 86: loss = 0.6065412759780884\n",
      "Epoch 87: loss = 0.6013280749320984\n",
      "Epoch 88: loss = 0.5983843803405762\n",
      "Epoch 89: loss = 0.5943615436553955\n",
      "Epoch 90: loss = 0.5942131280899048\n",
      "Epoch 91: loss = 0.5931912660598755\n",
      "Epoch 92: loss = 0.5889885425567627\n",
      "Epoch 93: loss = 0.5844202041625977\n",
      "Epoch 94: loss = 0.5816053748130798\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 95: loss = 0.5841403007507324\n",
      "Epoch 96: loss = 0.5787111520767212\n",
      "Epoch 97: loss = 0.5767002105712891\n",
      "Epoch 98: loss = 0.5712048411369324\n",
      "Epoch 99: loss = 0.5715557932853699\n",
      "/home/clive/work/seldon-core/fork-seldon-core/examples/models/nodejs_tensorflow\n",
      "\n",
      "\u001b[33m\u001b[39m\n",
      "\u001b[33m   ╭───────────────────────────────────────────────────────────────╮\u001b[39m\n",
      "   \u001b[33m│\u001b[39m                                                               \u001b[33m│\u001b[39m\n",
      "   \u001b[33m│\u001b[39m       New \u001b[33mminor\u001b[39m version of npm available! \u001b[31m6.4.1\u001b[39m → \u001b[32m6.9.0\u001b[39m       \u001b[33m│\u001b[39m\n",
      "   \u001b[33m│\u001b[39m   \u001b[33mChangelog:\u001b[39m \u001b[36mhttps://github.com/npm/cli/releases/tag/v6.9.0\u001b[39m   \u001b[33m│\u001b[39m\n",
      "   \u001b[33m│\u001b[39m               Run \u001b[32mnpm install -g npm\u001b[39m to update!               \u001b[33m│\u001b[39m\n",
      "   \u001b[33m│\u001b[39m                                                               \u001b[33m│\u001b[39m\n",
      "\u001b[33m   ╰───────────────────────────────────────────────────────────────╯\u001b[39m\n",
      "\u001b[33m\u001b[39m\n",
      "rm -rf node_modules\n",
      "rm -f package-lock.json\n"
     ]
    }
   ],
   "source": [
    "!make train && make clean_build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Training creates a model.json file and a weights.bin file which is utilized for prediction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prediction using REST API on the docker container"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---> Installing application source...\n",
      "---> Installing dependencies ...\n",
      "\n",
      "> @tensorflow/tfjs-node@0.1.15 install /microservice/model/node_modules/@tensorflow/tfjs-node\n",
      "> node scripts/install.js\n",
      "\n",
      "* Downloading libtensorflow\n",
      "\n",
      "* Building TensorFlow Node.js bindings\n",
      "\n",
      "> protobufjs@6.8.8 postinstall /microservice/model/node_modules/protobufjs\n",
      "> node scripts/postinstall\n",
      "\n",
      "npm notice created a lockfile as package-lock.json. You should commit this file.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No repository field.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No license field.\n",
      "\n",
      "added 48 packages from 56 contributors and audited 61 packages in 8.775s\n",
      "found 0 vulnerabilities\n",
      "\n",
      "Build completed successfully\n"
     ]
    }
   ],
   "source": [
    "!s2i build . seldonio/seldon-core-s2i-nodejs:0.2-SNAPSHOT node-s2i-model-image:0.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6cc8e4bca5aff59b1a4f0613f4e61ac212bd513954f4c61c964c0cb237a35f34\r\n"
     ]
    }
   ],
   "source": [
    "!docker run --name \"nodejs_tensorflow_predictor\" -d --rm -p 5000:5000 node-s2i-model-image:0.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Send some random features that conform to the contract"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------\r\n",
      "SENDING NEW REQUEST:\r\n",
      "\r\n",
      "[[5.742 7.559 0.876 8.28  0.631 5.414 0.392 0.822 8.55  9.548]]\r\n",
      "RECEIVED RESPONSE:\r\n",
      "data {\r\n",
      "  names: \"t:0\"\r\n",
      "  tensor {\r\n",
      "    shape: 1\r\n",
      "    shape: 1\r\n",
      "    values: -1.732214331626892\r\n",
      "  }\r\n",
      "}\r\n",
      "\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!seldon-core-tester contract.json 0.0.0.0 5000 -p -t"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nodejs_tensorflow_predictor\r\n"
     ]
    }
   ],
   "source": [
    "!docker rm nodejs_tensorflow_predictor --force"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prediction using GRPC API on the docker container"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---> Installing application source...\n",
      "---> Installing dependencies ...\n",
      "\n",
      "> @tensorflow/tfjs-node@0.1.15 install /microservice/model/node_modules/@tensorflow/tfjs-node\n",
      "> node scripts/install.js\n",
      "\n",
      "* Downloading libtensorflow\n",
      "\n",
      "* Building TensorFlow Node.js bindings\n",
      "\n",
      "> protobufjs@6.8.8 postinstall /microservice/model/node_modules/protobufjs\n",
      "> node scripts/postinstall\n",
      "\n",
      "npm notice created a lockfile as package-lock.json. You should commit this file.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No repository field.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No license field.\n",
      "\n",
      "added 48 packages from 56 contributors and audited 61 packages in 7.096s\n",
      "found 0 vulnerabilities\n",
      "\n",
      "Build completed successfully\n"
     ]
    }
   ],
   "source": [
    "!s2i build -E ./.s2i/environment_grpc . seldonio/seldon-core-s2i-nodejs:0.2-SNAPSHOT node-s2i-model-image:0.2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3e824d60a31f688ed8c5e7cc95cb6e15ff72669faec8e219d6fee3a900794007\r\n"
     ]
    }
   ],
   "source": [
    "!docker run --name \"nodejs_tensorflow_predictor\" -d --rm -p 5000:5000 node-s2i-model-image:0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Send some random features that conform to the contract"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------\n",
      "SENDING NEW REQUEST:\n",
      "\n",
      "[[8.196e+00 9.259e+00 8.349e+00 9.000e-03 5.450e+00 5.363e+00 2.453e+00\n",
      "  3.760e-01 4.719e+00 7.410e-01]]\n",
      "RECEIVED RESPONSE:\n",
      "data {\n",
      "  names: \"t:0\"\n",
      "  tensor {\n",
      "    shape: 1\n",
      "    shape: 1\n",
      "    values: 3.598963499069214\n",
      "  }\n",
      "}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!seldon-core-tester contract.json 0.0.0.0 5000 -p -t --grpc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nodejs_tensorflow_predictor\r\n"
     ]
    }
   ],
   "source": [
    "!docker rm nodejs_tensorflow_predictor --force"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test using Minikube\n",
    "\n",
    "**Due to a [minikube/s2i issue](https://github.com/SeldonIO/seldon-core/issues/253) you will need [s2i >= 1.1.13](https://github.com/openshift/source-to-image/releases/tag/v1.1.13)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!minikube start --memory 4096 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clusterrolebinding.rbac.authorization.k8s.io/kube-system-cluster-admin created\r\n"
     ]
    }
   ],
   "source": [
    "!kubectl create clusterrolebinding kube-system-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "$HELM_HOME has been configured at /home/clive/.helm.\n",
      "\n",
      "Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.\n",
      "\n",
      "Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.\n",
      "To prevent this, run `helm init` with the --tiller-tls-verify flag.\n",
      "For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation\n",
      "Happy Helming!\n"
     ]
    }
   ],
   "source": [
    "!helm init"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for deployment \"tiller-deploy\" rollout to finish: 0 of 1 updated replicas are available...\n",
      "deployment \"tiller-deploy\" successfully rolled out\n"
     ]
    }
   ],
   "source": [
    "!kubectl rollout status deploy/tiller-deploy -n kube-system"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME:   seldon-core\n",
      "LAST DEPLOYED: Fri May 10 07:06:05 2019\n",
      "NAMESPACE: seldon-system\n",
      "STATUS: DEPLOYED\n",
      "\n",
      "RESOURCES:\n",
      "==> v1/Secret\n",
      "NAME                                   TYPE    DATA  AGE\n",
      "seldon-operator-webhook-server-secret  Opaque  0     1s\n",
      "\n",
      "==> v1beta1/CustomResourceDefinition\n",
      "NAME                                         AGE\n",
      "seldondeployments.machinelearning.seldon.io  1s\n",
      "\n",
      "==> v1/ClusterRole\n",
      "seldon-operator-manager-role  0s\n",
      "\n",
      "==> v1/ClusterRoleBinding\n",
      "NAME                                 AGE\n",
      "seldon-operator-manager-rolebinding  0s\n",
      "\n",
      "==> v1/Service\n",
      "NAME                                        TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)  AGE\n",
      "seldon-operator-controller-manager-service  ClusterIP  10.104.23.226  <none>       443/TCP  0s\n",
      "\n",
      "==> v1/StatefulSet\n",
      "NAME                                DESIRED  CURRENT  AGE\n",
      "seldon-operator-controller-manager  1        1        0s\n",
      "\n",
      "==> v1/Pod(related)\n",
      "NAME                                  READY  STATUS             RESTARTS  AGE\n",
      "seldon-operator-controller-manager-0  0/1    ContainerCreating  0         0s\n",
      "\n",
      "\n",
      "NOTES:\n",
      "NOTES: TODO\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!helm install ../../../helm-charts/seldon-core-operator --name seldon-core --set usageMetrics.enabled=true   --namespace seldon-system"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for 1 pods to be ready...\n",
      "partitioned roll out complete: 1 new pods have been updated...\n"
     ]
    }
   ],
   "source": [
    "!kubectl rollout status deploy/seldon-controller-manager -n seldon-system"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setup Ingress\n",
    "Please note: There are reported gRPC issues with ambassador (see https://github.com/SeldonIO/seldon-core/issues/473)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME:   ambassador\n",
      "LAST DEPLOYED: Fri May 10 07:06:20 2019\n",
      "NAMESPACE: default\n",
      "STATUS: DEPLOYED\n",
      "\n",
      "RESOURCES:\n",
      "==> v1beta1/ClusterRole\n",
      "NAME        AGE\n",
      "ambassador  0s\n",
      "\n",
      "==> v1beta1/ClusterRoleBinding\n",
      "NAME        AGE\n",
      "ambassador  0s\n",
      "\n",
      "==> v1/Service\n",
      "NAME               TYPE          CLUSTER-IP      EXTERNAL-IP  PORT(S)                     AGE\n",
      "ambassador-admins  ClusterIP     10.102.250.208  <none>       8877/TCP                    0s\n",
      "ambassador         LoadBalancer  10.111.31.208   <pending>    80:31312/TCP,443:32348/TCP  0s\n",
      "\n",
      "==> v1/Deployment\n",
      "NAME        DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE\n",
      "ambassador  3        3        3           0          0s\n",
      "\n",
      "==> v1/Pod(related)\n",
      "NAME                         READY  STATUS             RESTARTS  AGE\n",
      "ambassador-5b89d44544-97jqg  0/1    ContainerCreating  0         0s\n",
      "ambassador-5b89d44544-lhd5t  0/1    ContainerCreating  0         0s\n",
      "ambassador-5b89d44544-nzr6d  0/1    ContainerCreating  0         0s\n",
      "\n",
      "==> v1/ServiceAccount\n",
      "NAME        SECRETS  AGE\n",
      "ambassador  1        0s\n",
      "\n",
      "\n",
      "NOTES:\n",
      "Congratuations! You've successfully installed Ambassador.\n",
      "\n",
      "For help, visit our Slack at https://d6e.co/slack or view the documentation online at https://www.getambassador.io.\n",
      "\n",
      "To get the IP address of Ambassador, run the following commands:\n",
      "NOTE: It may take a few minutes for the LoadBalancer IP to be available.\n",
      "     You can watch the status of by running 'kubectl get svc -w  --namespace default ambassador'\n",
      "\n",
      "  On GKE/Azure:\n",
      "  export SERVICE_IP=$(kubectl get svc --namespace default ambassador -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\n",
      "\n",
      "  On AWS:\n",
      "  export SERVICE_IP=$(kubectl get svc --namespace default ambassador -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')\n",
      "\n",
      "  echo http://$SERVICE_IP:\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!helm install stable/ambassador --name ambassador --set crds.keep=false"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for deployment \"ambassador\" rollout to finish: 0 of 3 updated replicas are available...\n",
      "Waiting for deployment \"ambassador\" rollout to finish: 1 of 3 updated replicas are available...\n",
      "Waiting for deployment \"ambassador\" rollout to finish: 2 of 3 updated replicas are available...\n",
      "deployment \"ambassador\" successfully rolled out\n"
     ]
    }
   ],
   "source": [
    "!kubectl rollout status deployment.apps/ambassador"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Build image and test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---> Installing application source...\n",
      "---> Installing dependencies ...\n",
      "\n",
      "> @tensorflow/tfjs-node@0.1.15 install /microservice/model/node_modules/@tensorflow/tfjs-node\n",
      "> node scripts/install.js\n",
      "\n",
      "* Downloading libtensorflow\n",
      "\n",
      "* Building TensorFlow Node.js bindings\n",
      "\n",
      "> protobufjs@6.8.8 postinstall /microservice/model/node_modules/protobufjs\n",
      "> node scripts/postinstall\n",
      "\n",
      "npm notice created a lockfile as package-lock.json. You should commit this file.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No repository field.\n",
      "npm WARN nodejs_tensorflow@1.0.0 No license field.\n",
      "\n",
      "added 48 packages from 56 contributors and audited 61 packages in 10.745s\n",
      "found 0 vulnerabilities\n",
      "\n",
      "Build completed successfully\n"
     ]
    }
   ],
   "source": [
    "!eval $(minikube docker-env) && s2i build . seldonio/seldon-core-s2i-nodejs:0.2-SNAPSHOT node-s2i-model-image:0.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "seldondeployment.machinelearning.seldon.io/seldon-deployment-example created\r\n"
     ]
    }
   ],
   "source": [
    "!kubectl create -f nodejs_tensorflow_deployment.json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiting for deployment \"seldon-cea8a97ce503f62508ad289c86fe0e27\" rollout to finish: 0 of 1 updated replicas are available...\n",
      "deployment \"seldon-cea8a97ce503f62508ad289c86fe0e27\" successfully rolled out\n"
     ]
    }
   ],
   "source": [
    "!kubectl rollout status deploy/seldon-cea8a97ce503f62508ad289c86fe0e27"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "----------------------------------------\n",
      "SENDING NEW REQUEST:\n",
      "\n",
      "[[8.804 4.565 8.703 3.414 6.527 2.084 4.716 0.56  0.08  6.324]]\n",
      "RECEIVED RESPONSE:\n",
      "meta {\n",
      "  puid: \"37h6oijvi0g2iu10hlvgcnojms\"\n",
      "  requestPath {\n",
      "    key: \"nodejs-tensorflow-predictor\"\n",
      "    value: \"node-s2i-model-image:0.1\"\n",
      "  }\n",
      "}\n",
      "data {\n",
      "  names: \"t:0\"\n",
      "  ndarray {\n",
      "    values {\n",
      "      list_value {\n",
      "        values {\n",
      "          number_value: -0.05151659995317459\n",
      "        }\n",
      "      }\n",
      "    }\n",
      "  }\n",
      "}\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!seldon-core-api-tester contract.json `minikube ip` `kubectl get svc ambassador -o jsonpath='{.spec.ports[0].nodePort}'` \\\n",
    "    seldon-deployment-example --namespace default -p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!minikube delete"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rm -rf node_modules\r\n",
      "rm -f package-lock.json\r\n",
      "rm -f model.json\r\n",
      "rm -f weights.bin\r\n"
     ]
    }
   ],
   "source": [
    "!make clean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
